/*
 * Copyright 2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package net.thick4.test.context;

import javax.servlet.ServletContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.context.support.AbstractContextLoader;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Webフレームワーク用の{@link org.springframework.test.context.ContextLoader}実装クラスです。
 * 
 * <p>
 * Web用のApplicationContext実装であるWebApplicationContext実装クラスをコンテキストして設定します。
 * また、{@link org.springframework.web.filter.RequestContextFilter}の動作をシミュレートし、
 * 作成したコンテキストに対してWeb用のスコープとして、Request, Sessionスコープを登録します。 
 * </p>
 */
public class GenericWebApplicationContextLoader extends AbstractContextLoader {

	protected static final Log logger = LogFactory.getLog(GenericWebApplicationContextLoader.class);
	
	/**
	 * locationsで指定されたSpring定義ファイルからSpringのApplicationContextを作成します。
	 * 
	 * <p>
	 * {@link org.springframework.web.context.WebApplicationContext}実装クラスのインスタンスを作成します。</li>
	 * </p>
	 * 
	 * @return WebApplicationContextの実装クラスを作成して返します
	 * @see org.springframework.test.context.ContextLoader#loadContext
	 */
	public ConfigurableApplicationContext loadContext(String... locations) throws Exception {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading ApplicationContext for locations [" +
					StringUtils.arrayToCommaDelimitedString(locations) + "].");
		}
		ContextLoader contextLoader = new ContextLoader();
		MockServletContext servletContext = new MockServletContext(); 
		String configLocationParam = StringUtils.arrayToCommaDelimitedString(locations);
		servletContext.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM, configLocationParam);
		ConfigurableWebApplicationContext context = (ConfigurableWebApplicationContext) contextLoader.initWebApplicationContext(servletContext);
		doFilter(context, servletContext);
		return context;
	}

	/**
	 * &quot;<code>-context.xml</code>&quot;を返します。
	 *
	 * @see org.springframework.test.context.support.AbstractContextLoader#getResourceSuffix()
	 */
	@Override
	protected String getResourceSuffix() {
		return "-context.xml";
	}
	
	/**
	 * {@link org.springframework.web.filter.RequestContextFilter}の動作をシミュレートし、
	 * 作成したコンテキストに対してWeb用のスコープとして、Request, Sessionスコープを登録します。
	 * 
	 * @param context WebApplicationContext
	 * @param servletContext ServletContext
	 */
	protected void doFilter(ConfigurableWebApplicationContext context, ServletContext servletContext) {
		MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
		
		ServletRequestAttributes attributes = new ServletRequestAttributes(request);
		LocaleContextHolder.setLocale(request.getLocale(), false);
		RequestContextHolder.setRequestAttributes(attributes, false);
		
		if (logger.isDebugEnabled()) {
			logger.debug("Bound request context to thread: " + request);
		}
	}

}
